package cn.springBoot.controller;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstanceQuery;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ljx
 * @description: 流程实例
 * @class cn.springBoot.controller.ProcessInstance
 * @create date: 2021/9/16
 *
 *         流程定义：通过资源文件，获取已事先定义好的流程规则信息。 执行实例：发起流程定义，可以认为流程定义就像定义了一个类，而执行实例就是生成了一个对象。 流程实例：一个流程的最长分支，就好比项目管理里面的关键路径。
 */
@RestController
@RequestMapping("/instance")
public class ProcessInstanceController {

    // 管理运行实例，用事件来trigger流程往后走
    @Autowired
    RuntimeService runtimeService;

    @Autowired
    RepositoryService repositoryService;

    // 身份验证
    @Autowired
    IdentityService identityService;

    @Autowired
    TaskService taskService;

    /**
     * @description: 启动流程实例
     * @param:key
     * @author: ljx
     * @create date: 2021/9/16
     * @version: V1.0
     * @return: boolean 启动实例的方式
     *
     *          processDefinitionKey processDefinitionKey + 租户ID messageName + 租户ID messageName processDefinitionId
     *
     *          当流程实例启动时，以下两张表会有新的数据插入：
     *
     *          ACT_RU_EXECUTION ACT_RU_TASK
     *
     *          同时会有几张历史表也会插入数据（ACT_HI_XXXX都是历史表）：
     *
     *          ACT_HI_ACTINST ACT_HI_TASKINST ACT_HI_PROCINST ACT_HI_IDENTITYLINK
     *
     */

    @GetMapping(value = "/startInstance")
    public boolean startInstance(String key) {
        // 根据key启动流程实例 这个KEY可以在数据库表 ACT_RE_PROCDEF 的KEY_字段查看到，当然也可以在流程文件中查到，或者通过查询接口查到。
        // 开启流程 需要指定当前用户
        // 设置当前用户为操作人
        identityService.setAuthenticatedUserId("admin");
        ProcessInstance simpleTest = runtimeService.startProcessInstanceByKey(key);
        System.out.println("流程实例的ProcessInstanceId: " + simpleTest.getId());
        System.out.println("流程实例的ProcessDefinitionId: " + simpleTest.getProcessDefinitionId());
        System.out.println("————————————————————————————————————————————————————");
        // 指定变量启动
        /* Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("userId", "张翠山");
        runtimeService.startProcessInstanceByKey("leave", variables);*/
        // 根据消息启动
        /* String messageName = "msg1";//或  String messageName = "msg2";
        runtimeService.startProcessInstanceByMessage(messageName);*/

        if (simpleTest != null && StringUtils.isNotBlank(simpleTest.getProcessDefinitionId())) {
            List<Task> list =
                taskService.createTaskQuery().processInstanceId(simpleTest.getProcessInstanceId()).active().list();

            for (Task task : list) {
                System.out.println("name:" + task.getName());
                System.out.println("id:" + task.getId());
                System.out.println("ProcessDefinitionId" + task.getProcessDefinitionId());
                System.out.println("taskDefinitionKey" + task.getTaskDefinitionKey());
                System.out.println("当前任务执行人:" + task.getAssignee());

            }

        }

        return true;
    }

    /**
     * @description: 正在进行的流程实例对象
     * @param:
     * @author: ljx
     * @create date: 2021/9/16
     * @version: V1.0
     * @return: java.util.List<org.camunda.bpm.engine.runtime.ProcessInstance>
     */

    @GetMapping("/getInstanceList")
    public List<ProcessInstance> getInstanceList() {
        // 流程实例查询对象，查询的是act_ru_execution表
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
        // query.processDefinitionKey("qjlc");//按照key进行过滤
        query.orderByProcessDefinitionId().desc();// 降序
        // query.listPage(0,2);//分页
        List<ProcessInstance> list = query.list();
        for (ProcessInstance processInstance : list) {
            System.out.println("key:" + processInstance.getBusinessKey() + " processInstanceId:"
                + processInstance.getId() + " processInstanceId:" + processInstance.getProcessInstanceId());// 获取正在运行的id

            System.out.println(
                "全局参数:starter " + runtimeService.getVariable("6ade2265-3d3b-11ec-97fd-00ff0eca940e", "starter"));// 获取正在运行的id
        }

        return null;
    }

    /**
     * @description: 删除流程实例
     * @param:processId
     * @Param: reason
     * @author: ljx
     * @create date: 2021/9/16
     * @version: V1.0
     * @return: void
     *
     *          这个过程中会涉及到如下数据库表操作： 删除：
     *
     *          ACT_RU_TASK ACT_RU_EXECUTION 更新：
     *
     *          ACT_HI_ACTINST ACT_HI_PROCINST ACT_HI_TASKINST
     */

    public void delInstance(String processId, String reason) {
        runtimeService.deleteProcessInstance(processId, reason);
    }

    /**
     * 挂起流程定义，挂起后基于该定义的流程将不能再执行，除非先激活
     *
     * @param id
     */
    public void suspendProcessDef1(String id) {
        runtimeService.suspendProcessInstanceByProcessDefinitionId(id);
    }

    /**
     * 挂起流程定义，挂起后基于该定义的流程将不能再执行，除非先激活
     *
     * 两种挂起方式
     *
     * @param id
     */
    public void suspendProcessDef2(String id) {
        // runtimeService.suspendProcessInstanceByProcessDefinitionId(id);
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        processInstanceQuery.processInstanceId(id);
        runtimeService.updateProcessInstanceSuspensionState().byProcessInstanceQuery(processInstanceQuery)
            .suspendAsync();
    }

    /**
     * 两种激活流程定义的方法
     * 
     * @param id
     */
    public void activeProcessDef(String id) {
        // repositoryService.activateProcessDefinitionById(id);
        repositoryService.updateProcessDefinitionSuspensionState().byProcessDefinitionId(id)
            .includeProcessInstances(true).activate();

        long first = 1000000000000L;
        int second = (int)first + 2;
    }

}
